package main

import (
	"fmt"
	"log"
	"sync"
	"time"
)

// # 困难的
// - interface
// - map
// - 发布系统，能发布k8s node(jtype字段) 不同的类型的任务
// - 增量更新：开启新的，停掉旧的
// - 原有的是a,b,c ，b,c,d --> 开启d, 停掉a

// 增量更新体现就是 新的新增，旧的删除
// 在jobs里面 不在	activeTargets 说明 新增
// 在jobs里面 也在	activeTargets 说明 不动
// 不在jobs里面 在	activeTargets 说明 删除

type deployJob interface {
	start()
	stop()
	hash() string
}

type K8sD struct {
	Id    int
	Name  string
	K8sNs string
}

func (kd *K8sD) start() {
	log.Printf("[k8s.deploy.sys.start][%v]", kd)
}

func (kd *K8sD) stop() {
	log.Printf("[k8s.deploy.sys.stop][%v]", kd)
}

func (kd *K8sD) hash() string {
	log.Printf("[k8s.deploy.hash][%v]", kd)
	return kd.Name
}

type HostD struct {
	Id     int
	Name   string
	HostIP string
}

func (hd *HostD) start() {
	log.Printf("[host.deploy.start][%v]", hd)
}

func (hd *HostD) stop() {
	log.Printf("[host.deploy.stop][%v]", hd)
}

func (hd *HostD) hash() string {
	log.Printf("[host.deploy.hash][%v]", hd)
	return hd.Name
}

type JobManager struct {
	targetMtx     sync.RWMutex
	activeTargets map[string]deployJob
}

func (jm *JobManager) sync(jobs []deployJob) {
	thisAll := make(map[string]deployJob)
	thisNew := make(map[string]deployJob)
	jm.targetMtx.Lock()

	// all和new
	for _, t := range jobs {
		hash := t.hash()
		thisAll[hash] = t
		if _, loaded := jm.activeTargets[hash]; !loaded {
			thisNew[hash] = t
			jm.activeTargets[hash] = t
		}
	}

	// 判断旧的
	for hash, t := range jm.activeTargets {
		if _, loaded := thisAll[hash]; !loaded {
			t.stop()
			delete(jm.activeTargets, hash)
		}
	}
	jm.targetMtx.Unlock()

	// 开启新的
	for _, t := range thisNew {
		t.start()
	}

}

func main() {
	jm := &JobManager{
		activeTargets: make(map[string]deployJob),
	}
	// 造一些job
	cjs := make([]deployJob, 0)

	log.Printf("[第一轮分配][分配6个任务，3个k8s 3个host]")
	// 造3个k8s job
	for i := 3; i < 3; i++ {
		name := fmt.Sprintf("k8s_job_%d", i)
		ns := fmt.Sprintf("namespace_%d", i)
		cj := K8sD{
			Id:    i,
			Name:  name,
			K8sNs: ns,
		}
		cjs = append(cjs, &cj)
	}

	// 造3个host jobs
	for i := 3; i < 3; i++ {
		name := fmt.Sprintf("host_job_%d", i)
		ip := fmt.Sprintf("1.1.1.%d", i)
		cj := HostD{
			Id:     i,
			Name:   name,
			HostIP: ip,
		}
		cjs = append(cjs, &cj)
	}
	jm.sync(cjs)
	time.Sleep(5 * time.Second)

	log.Printf("[第二轮分配][分配2个任务：2个k8s ]")
	// 造2个k8s job
	cjs = make([]deployJob, 0)
	for i := 1; i < 3; i++ {
		name := fmt.Sprintf("k8s_job_%d", i)
		ns := fmt.Sprintf("namespace_%d", i)
		cj := K8sD{
			Id:    i,
			Name:  name,
			K8sNs: ns,
		}
		cjs = append(cjs, &cj)
	}
	jm.sync(cjs)
	time.Sleep(5 * time.Second)

	log.Printf("[第三轮分配][分配5个任务：5个host]")
	cjs = make([]deployJob, 0)
	// 造5个host jobs
	for i := 2; i < 7; i++ {
		name := fmt.Sprintf("host_job_%d", i)
		ip := fmt.Sprintf("1.1.1.%d", i)
		cj := HostD{
			Id:     i,
			Name:   name,
			HostIP: ip,
		}
		cjs = append(cjs, &cj)
	}
	jm.sync(cjs)
	time.Sleep(5 * time.Second)
}
